package com.tiger.project.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.tiger.common.core.redis.RedisCache;
import com.tiger.common.exception.CustomException;
import com.tiger.common.utils.Code;
import com.tiger.common.utils.DateUtils;
import com.tiger.common.utils.StringUtils;
import com.tiger.project.domain.*;
import com.tiger.project.domain.vo.*;
import com.tiger.project.mapper.*;
import com.tiger.project.service.IAssetService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.NumberFormat;
import java.time.LocalDate;
import java.util.*;

import static java.util.Comparator.comparingInt;

/**
 * 【资产列表】Service业务层处理
 *
 * @author standard
 * @date 2022-09-15
 */
@Service
public class AssetServiceImpl implements IAssetService {
    @Autowired
    private AssetMapper assetMapper;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private AssetEnclosureMapper assetEnclosureMapper;
    @Autowired
    private AssetHistoryMapper assetHistoryMapper;
    @Autowired
    private AssetRegionalDivisionMapper divisionMapper;
    @Autowired
    private PatrolRecordMapper patrolRecordMapper;
    @Autowired
    private MaintenanceApplyMapper maintenanceApplyMapper;
    @Autowired
    private ContractSponsorMapper contractSponsorMapper;

    /**
     * 查询【资产列表】
     *
     * @param id 【资产列表】主键
     * @return 【资产列表】
     */
    @Override
    public Asset selectAssetById(Long id) {
        Asset asset = assetMapper.selectAssetById(id);
        //附件
        AssetEnclosure assetEnclosure = new AssetEnclosure();
        assetEnclosure.setAssetId(id);
        List<AssetEnclosure> list = assetEnclosureMapper.selectAssetEnclosureList(assetEnclosure);
        if (list != null && list.size() > 0){
            asset.getEnclosureList().addAll(list);
        }
        //资产变更记录
        AssetHistory assetHistory = new AssetHistory();
        assetHistory.setAssetId(id);
        List<AssetHistory> historyList = assetHistoryMapper.selectAssetHistoryList(assetHistory);
        if (historyList != null && historyList.size() > 0){
            asset.getHistoryList().addAll(historyList);
        }
        //面积划分
        AssetRegionalDivision division = new AssetRegionalDivision();
        division.setAssetId(id);
        List<AssetRegionalDivision> divisionList = divisionMapper.selectAssetRegionalDivisionList(division);
        if (divisionList != null && divisionList.size() > 0){
            asset.getRegionalDivisionList().addAll(divisionList);
        }
        //巡查
        PatrolRecord patrolRecord = new PatrolRecord();
        patrolRecord.setAssetId(id);
        List<PatrolRecord> recordList = patrolRecordMapper.selectPatrolRecordList(patrolRecord);
        if (recordList != null && recordList.size() > 0){
            asset.getPatrolRecordList().addAll(recordList);
        }
        //维修
        MaintenanceApply maintenanceApply = new MaintenanceApply();
        maintenanceApply.setAssetId(id);
        List<MaintenanceApply> maintenanceApplyList = maintenanceApplyMapper.selectMaintenanceApplyList(maintenanceApply);
        if (maintenanceApplyList != null && maintenanceApplyList.size() > 0){
            asset.getMaintenanceApplyList().addAll(maintenanceApplyList);
        }
        return asset;
    }

    /**
     * 查询【资产列表】列表
     *
     * @param asset 【资产列表】
     * @return 【资产列表】
     */
    @Override
    public List<Asset> selectAssetList(Asset asset) {
        List<Asset> assetList = assetMapper.selectAssetList(asset);
        for (Asset a : assetList){
            List<ContractSponsor> sponsorList = contractSponsorMapper.selectByAssetId(a.getId(), a.getCompanyId());
            a.setContractSponsorList(sponsorList);
        }
        return assetList;
    }


    //关联资产
    @Override
    public List<Asset> selectAssetBookList(Asset asset) {
        return assetMapper.selectAssetBookList(asset);
    }

    /**
     * 新增【资产列表】
     *
     * @param asset 【资产列表】
     * @return 结果
     */
    @Override
    public int insertAsset(Asset asset) {
        int code = redisCache.getCacheObjectCode(LocalDate.now().format(Code.fmt) + "zc");
        addCode(code);
        if (asset.getCategory() == 1){ //房产
            asset.setAssetNo(String.format("%s-%s%04d", "CKFC","GR-", code));
        }else {     //地产
            asset.setAssetNo(String.format("%s-%s%04d", "CKDC","GR-", code));
        }
        asset.setCreatedAt(DateUtils.getNowDate());
        asset.setIsDeleted(0L);
        int i = assetMapper.insertAsset(asset);
        change(asset);
        return i;
    }

    /**
     * 修改【资产列表】
     *
     * @param asset 【资产列表】
     * @return 结果
     */
    @Override
    public int updateAsset(Asset asset) {
        change(asset);
        asset.setUpdatedAt(DateUtils.getNowDate());
        return assetMapper.updateAsset(asset);
    }

    /**
     * 批量删除【资产列表】
     *
     * @param ids 需要删除的【资产列表】主键
     * @return 结果
     */
    @Override
    public int deleteAssetByIds(Long[] ids) {
        for (Long id : ids){
            int i = assetMapper.relevancyAsset(id);
            if (i > 0){
                throw new CustomException("关联巡查，维修，合同，水电的资产不可以删除");
            }
        }
        return assetMapper.deleteAssetByIds(ids);
    }

    /**
     * 删除【资产列表】信息
     *
     * @param id 【资产列表】主键
     * @return 结果
     */
    @Override
    public int deleteAssetById(Long id) {
        return assetMapper.deleteAssetById(id);
    }

    @Override
    public AssetCountResp listCount(Integer companyId) {
        int houseAssetNum = 0;
        int landAssetNum = 0;
        int allNum = 0;
        AssetCountResp resp = new AssetCountResp();
        List<Map<String, Object>> list = assetMapper.selectAssetCountListByCategory(companyId);
        dealList(list);
        houseAssetNum = CollectionUtil.isEmpty(list) ? houseAssetNum :
                list.stream().mapToInt(h -> ((BigDecimal) h.get("house")).intValue()).sum();
        landAssetNum = CollectionUtil.isEmpty(list) ? landAssetNum :
                list.stream().mapToInt(h -> ((BigDecimal) h.get("land")).intValue()).sum();
        allNum = CollectionUtil.isEmpty(list) ? allNum :
                list.stream().mapToInt(h -> ((Long) h.get("total")).intValue()).sum();
        list.sort(comparingInt(o -> (int) o.get("year")));
        resp.setAssetList(list);
        resp.setHouseAssetNum(houseAssetNum);
        resp.setLandAssetNum(landAssetNum);
        resp.setAllNum(allNum);
        return resp;
    }

    @Override
    public AssetRentCountResp rentCount(Integer companyId) {
        AssetRentCountResp resp = new AssetRentCountResp();
        Map leasedCountMap = assetMapper.getLeasedCount(companyId);
        Map unLeasedCountMap = assetMapper.getUnLeasedCount(companyId);
        int letNum = Math.toIntExact((Long) leasedCountMap.get("letNum"));//已出租个数
        int unletNum = Math.toIntExact((Long) unLeasedCountMap.get("unletNum"));//未出租个数
        int allNum = letNum + unletNum;
        double letCount = (double)letNum / allNum;
        double unletCount = (double)unletNum / allNum;
        NumberFormat nt = NumberFormat.getPercentInstance();
        nt.setMinimumFractionDigits(2);
        resp.setLeasedPercent(nt.format(letCount));
        resp.setUnLeasedPercent(nt.format(unletCount));
        resp.setAllLeasedNum(letNum);
        resp.setHouseLeasedNum(Math.toIntExact((Long)leasedCountMap.get("houseNum")));
        resp.setLandLeasedNum(Math.toIntExact((Long)leasedCountMap.get("landNum")));
        return resp;
    }

    @Override
    public ContractAnalysisVO contractAnalysisCount(String contractType, Integer companyId) {
        return assetMapper.contractAnalysisCount(contractType,companyId);
    }

    @Override
    public ContractCountResp contractCount(Integer companyId) {
        ContractCountResp resp = new ContractCountResp();
        List<Map<String, Object>> list = assetMapper.selectContractCount(companyId);
        dealList(list);
        list.sort(comparingInt(o -> (int) o.get("year")));
        resp.setContractList(list);
        return resp;
    }

    @Override
    public ContractPerformanceResp getPerformanceOfContract(Integer companyId) {
        ContractPerformanceResp resp = assetMapper.getPerformanceOfContract(companyId);
        return resp;
    }

    @Override
    public List<ContractOverdueRankingResp> getContractOverdueRanking(Integer companyId) {
        return assetMapper.getContractOverdueRanking(companyId);
    }

    @Override
    public List<AssetUsageVO> contractAnalysisPageList(String contractType, Integer companyId, String contractType1, Date startTime, Date endTime) {
        return assetMapper.contractAnalysisPageList(contractType,companyId,startTime,endTime);
    }

    @Override
    public List<Map<String, Object>> getHouseReceiptList(Integer companyId) {
        return assetMapper.selectHouseAssetReceiptMoneyList(companyId,DateUtil.date().year(),1);
    }

    @Override
    public List<Map<String, Object>> getLandReceiptList(Integer companyId) {
        return assetMapper.selectHouseAssetReceiptMoneyList(companyId,DateUtil.date().year(),2);
    }

    @Override
    public List<Asset> idlePage( Asset asset) {
        return assetMapper.selectIdleAssetPage( asset);
    }

    @Override
    public List<Asset> idleList(Long companyId) {
        Asset asset = new Asset();
        return assetMapper.selectIdleAssetList(asset);
    }

    @Override
    public List<RentAssetVO> rentList(Long companyId) {
        Asset asset = new Asset();
        asset.setCompanyId(companyId);
        int year = DateUtil.date().year();
        return assetMapper.selectRentAssetList(asset, DateUtil.date().year(),year-1);
    }

    @Override
    public List<RentAssetVO> rentPage(Long companyId) {
        Asset asset = new Asset();
        asset.setCompanyId(companyId);
        int year = new Date().getYear();
        return assetMapper.selectRentAssetPage(asset,(year+1),year);
    }

    @Override
    public AssetStatisticsVO getStatistics(Asset asset) {
        return assetMapper.selectAssetStatistics(asset);
    }

    @Override
    public List<MonitorAssetVO> monitorAssetPage( Asset asset) {
        List<MonitorAssetVO> monitorAssetPage = this.assetMapper.selectMonitorAssetPage(asset);
        return monitorAssetPage;
    }

    @Override
    public List<AssetStatisticsExportVO> landExportList(Long companyId) {

        return this.assetMapper.selectAssetExportList(2,companyId);
    }

    @Override
    public List<AssetStatisticsBasicVO> landBasicPage(Long companyId) {

        return this.assetMapper.selectAssetBasicPage(2,companyId);
    }

    @Override
    public List<AssetStatisticsUsedVO> landUsedPage(Long companyId) {
        return this.assetMapper.selectAssetUsedPage(2,companyId);
    }

    @Override
    public List<AssetStatisticsExportVO> houseExportList(Long companyId) {
        return this.assetMapper.selectAssetExportList(1,companyId);
    }

    @Override
    public List<AssetStatisticsBasicVO> houseBasicPage(Long companyId) {
        return this.assetMapper.selectAssetBasicPage(1,companyId);
    }

    @Override
    public List<AssetStatisticsUsedVO> houseUsedPage(Long companyId) {
        return this.assetMapper.selectAssetUsedPage(1,companyId);
    }

    /**
     *  房屋空置天数排名： 排前十，无关联合同不排，且可租面积>0
     * @param companyId
     * @return 返回
     */
    @Override
    public List<Map<String, Object>> getVacantHouseList(Long companyId) {
        return this.assetMapper.selectVacantHouseList(companyId);
    }

    /**
     *  总资产收益率: 总租金/可出租资产资产总价值（房屋价值）
     * @param companyId
     * @return 返回
     */
    @Override
    public Map<String, Object> getReturnOnTotalAssets(Long companyId) {
        return this.assetMapper.selectReturnOnTotalAssets(companyId);
    }

    /**
     *  资产分类
     * @param companyId
     * @return 返回
     */
    @Override
    public List<Map<String, Object>> getAssetsCategory(Long companyId) {
        return this.assetMapper.selectAssetsCategory(companyId);
    }


    /**
     * 查询资产面积和资产价值
     *
     * @param companyId 公司id
     * @return 【资产面积】集合
     */
    @Override
    public List<Map<String, Object>> getAssetAreaAndValue(Long companyId) {
        List<Map<String, Object>> list = assetMapper.selectAssetArea(companyId);
        Map<String, Object> area = packageAsset(list);
        list = assetMapper.selectAssetValue(companyId);
        Map<String, Object> value = packageAsset(list);
        return Arrays.asList(area, value);
    }

    /**
     * 查询被占用资产
     *
     * @param companyId 公司id
     * @return 【资产价值】集合
     */
    @Override
    public List<Map<String, Object>> getBeOccupiedAsset(Integer companyId) {
        return assetMapper.selectBeOccupiedAsset(companyId);
    }


    Map<String, Object> packageAsset(List<Map<String, Object>> list) {
        Map<String, Object> res = new HashMap<>();
        res.put("house", new BigDecimal(0));
        res.put("land", new BigDecimal(0));
        for (Map l:list) {
            if (l.get("category") == null || l.get("area") == null) {
                continue;
            }
            BigDecimal area = new BigDecimal(l.get("area").toString());
            if ((int)l.get("category") == 1) {
                res.put("house", area);
            }
            if ((int)l.get("category") == 2) {
                res.put("land", area);
            }
        }
        BigDecimal total = ((BigDecimal)res.get("house")).add((BigDecimal)res.get("land"));
        res.put("total", total);
        return res;
    }

    /**
     *  资产出租比例
     * @param companyIds
     * @return 返回
     */
    public List<AssetMonth> getAssetsMonth(List<Long> companyIds) {
        List<Map<String, Object>> rentableArea = assetMapper.selectRentableArea(companyIds);
        List<Map<String, Object>> leasedArea = assetMapper.selectLeasedArea(companyIds);
        List<AssetMonth> res = new ArrayList<>();
        for (Map r:rentableArea) {
            long companyIdR = (long)r.get("company_id");
            for (Map l:leasedArea) {
                long companyIdL = (long)l.get("company_id");
                if (companyIdR == companyIdL) {
//                    BigDecimal rate = new BigDecimal(r.get("total").toString()).
//                            divide(new BigDecimal(l.get("total").toString()), 4, RoundingMode.DOWN);
                    BigDecimal tenantable = new BigDecimal(r.get("total").toString());
                    BigDecimal leased = new BigDecimal(l.get("total").toString());
                    BigDecimal rate = tenantable.divide(leased, 4, RoundingMode.DOWN);
                    AssetMonth item = new AssetMonth();
                    item.setCompanyId(companyIdR);
                    item.setTenantable(tenantable);
                    item.setLeased(leased);
                    item.setRate(rate);
                    res.add(item);
                }
            }
        }
        return res;
    }

    private void change(Asset asset){
        //附件
        assetEnclosureMapper.deleteAssetEnclosureByAssetId(asset.getId());
        if (StringUtils.isNotEmpty(asset.getEnclosureList())){
            asset.getEnclosureList().forEach(item -> {
                item.setAssetId(asset.getId());
                item.setState(1);//上传成功
                item.setCreatedAt(DateUtils.getNowDate());
                assetEnclosureMapper.insertAssetEnclosure(item);
            });
        }

        //资产变更记录
        assetHistoryMapper.deleteAssetHistoryByAssetId(asset.getId());
        if (StringUtils.isNotEmpty(asset.getHistoryList())){
            asset.getHistoryList().forEach(assetHistory -> {
                assetHistory.setAssetId(asset.getId());
                assetHistory.setCreatedAt(DateUtils.getNowDate());
                assetHistoryMapper.insertAssetHistory(assetHistory);
            });
        }

        //面积划分
        divisionMapper.deleteAssetRegionalDivisionByAssetId(asset.getId());
        if (StringUtils.isNotEmpty(asset.getRegionalDivisionList())){
            asset.getRegionalDivisionList().forEach(assetRegionalDivision -> {
                assetRegionalDivision.setAssetId(asset.getId());
                assetRegionalDivision.setCreatedAt(DateUtils.getNowDate());
                divisionMapper.insertAssetRegionalDivision(assetRegionalDivision);
            });
        }
    }

    /**
     * 生成编码
     */
    private synchronized void addCode(int code) {
        redisCache.setCacheObject(LocalDate.now().format(Code.fmt) + "zc", code + 1);
    }

    private void dealList(List<Map<String, Object>> list){
        int currentYear = DateUtil.date().year();
        for (int i = 0; i < 5; i++) {
            int currentLoopYear = currentYear-i;
            if (list.stream().noneMatch(m -> (int)m.get("year")==currentLoopYear)) {
                Map<String, Object> map = null;
                map = new HashMap<String, Object>(4) {
                    {
                        put("year", currentLoopYear);
                        put("total",new Long(0));
                        put("land", BigDecimal.ZERO);
                        put("house",BigDecimal.ZERO);
                    }
                };
                list.add(map);
            }
        }
    }
}
